package mspbots.timedoctor.client.core.client;

import com.fasterxml.jackson.databind.JsonNode;
import mspbots.timedoctor.client.core.BaseGenericService;
import mspbots.timedoctor.client.exception.BadRequestException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Map;
import java.util.function.Function;

/**
 * com.mspbots.api.client.A
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/11/12
 */
public abstract class AbstractClient extends BaseGenericService implements BaseClient {

    protected WebClient webClient;

    protected AbstractClient(WebClient webClient) {
        this.webClient = webClient;
    }

    @Override
    public <T> Mono<T> post(Function<UriBuilder, URI> path, Object body, Class<T> responseType) {
        return this.webClient.post()
                .uri(path)
                .accept(MediaType.APPLICATION_JSON)
                .bodyValue(body)
                .retrieve()
                .bodyToMono(responseType);
    }

    @Override
    public <T> Flux<T> postFlux(Function<UriBuilder, URI> path, Object body, Class<T> responseType) {
        return this.webClient.post()
                .uri(path)
                .accept(MediaType.APPLICATION_JSON)
                .bodyValue(body)
                .retrieve()
                .bodyToFlux(responseType);
    }


    @Override
    public <T> Mono<T> get(String path, Map<String, Object> params, Class<T> responseType) {
        return this.webClient.get()
                .uri(uriBuilder -> uriBuilder.path(path).queryParams(ClientUtils.form(params)).build())
                .attribute("tenantId", params.get("tenantId"))
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .onStatus(HttpStatus::isError, clientResponse -> clientResponse.bodyToMono(JsonNode.class)
                        .flatMap(jsonNode -> Mono.error(new BadRequestException(clientResponse.rawStatusCode(), jsonNode.toString()))))
                .bodyToMono(responseType);
    }

    @Override
    public <T> Flux<T> getFlux(Function<UriBuilder, URI> path, Class<T> responseType) {
        return this.webClient.get()
                .uri(path)
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToFlux(responseType);
    }

    @Override
    public <T> Mono<T> put(String path, Object body, Class<T> responseType) {
        return this.webClient.put()
                .uri(uriBuilder -> uriBuilder.path(path).build())
                .bodyValue(body)
                .retrieve()
                .bodyToMono(responseType);
    }

    @Override
    public <T> Mono<T> delete(String path, Map<String, Object> params, Class<T> responseType) {
        return this.webClient.delete()
                .uri(uriBuilder -> uriBuilder.path(path)
                        .queryParams(ClientUtils.form(params))
                        .build())
                .retrieve()
                .bodyToMono(responseType);
    }

}
